﻿using libC.semantic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace libC.translate
{
    /// <summary>
    /// C 语言 wrap code 生成器
    /// </summary>
    internal class generatorC : IWrapGenerator, IDisposable
    {

        public string nameSpace;
        public string className;
        public string dllFile;

        private semanticAnalyzer _semAnaly;
        private string _code;   //.h code
        private string _code_c; //.c cdoe
        private int indentLevel = 0;
        private int indentLevel_c = 0;
        private string indentSP => transTool.indentSp(indentLevel);
        private string indentSP_c => transTool.indentSp(indentLevel_c);

        private const string TDF = "typedef";
        private const string DE = "dele";
        private const string ETN = "extern";
        private const string lDll = "LoadDLL";
        

        private List<string> includeList_h = new List<string> { "<cstdint>" };
        private List<string> includeList_c = new List<string> { "<Windows.h>", "<stdio.h>" };

        private void init()
        {
            _code = "";
            _semAnaly = null;
        }

        public string getWrapCode()
        {
            return _code + tools.CODESPLITE + _code_c;
        }

        public void parse(semanticAnalyzer semAnaly)
        {
            //初始化状态
            init();
            //
            _semAnaly = semAnaly;

            //遍历树 ， 筛选 有 （extern "C"）导出标记的函数
            var funIdsDic = new Dictionary<uint, List<uint>>();
            //分析 返回值 、参数定义 ， 收集相关 用户自定义类型
            var cTypeDic = new Dictionary<uint, List<uint>>();
            transTool.limitFun(_semAnaly, funIdsDic, cTypeDic);
            //写文本
            //头信息
            transTool.addHaedInfomation(ref _code);
            transTool.addHaedInfomation(ref _code_c);
            //包含的
            addStrInclude();
            //写文本
            if (!string.IsNullOrEmpty(nameSpace))
            {
                addStrNameSpace(nameSpace);     //增加class 字符串
            }

            //loadDll 方法声明
            _code += $"{indentSP}int {lDll}();{transTool.LF}";

            //写 枚举、结构体
            insertCTypesDic(cTypeDic);

            //写 函数 ,语言基础类型 映射
            insertFunsDic(funIdsDic);
            //nameSpace
            if (!string.IsNullOrEmpty(nameSpace))
            {
                addStrBlockEnd();
                addStrBlockEnd(true);
            }
        }
        private void addStrInclude()
        {
            foreach (var item in includeList_h)
            {
                _code += $"#include {item}{transTool.LF}";
            }

            var arr = includeList_c.ToList();
            arr.Add($"\"{className}.h\"");
            foreach (var item in arr)
            {
                _code_c += $"#include {item}{transTool.LF}";
            }
        }

        //添加 块 } 结尾
        private void addStrBlockEnd(bool isCPP = false)
        {
            if (isCPP)
            {
                indentLevel_c--;
                _code_c += $"{indentSP_c}}}{transTool.LF}";
            }
            else
            {
                indentLevel--;
                _code += $"{indentSP}}}{transTool.LF}";
            }
        }
        //添加 命名空间 字符串
        private void addStrNameSpace(string ns)
        {
            _code += $"{transTool.NSP} {ns} {"{"}{transTool.LF}";
            indentLevel++;
            _code_c += $"{transTool.NSP} {ns} {"{"}{transTool.LF}";
            indentLevel_c++;
        }
        private void insertCTypesDic(Dictionary<uint, List<uint>> cTypeDic)
        {
            _code += $"//自定义类型 {transTool.LF}";
            foreach (var item in cTypeDic)
            {
                //单个 ast
                uint astTd = item.Key;
                var cTypes = item.Value;
                var semAst = _semAnaly.getSemantAst(astTd);
                for (int i = 0, len = cTypes.Count; i < len; i++)
                {
                    insertCType(semAst, cTypes[i]);
                }
            }
        }

        private void insertCType(semanticAST semAst, uint _nodeId)
        {
            var _info = semAst.getSemantInfo(_nodeId);
            switch (_info.getType())
            {
                //case SemanticInfoType.EXPR:
                //    break;
                //case SemanticInfoType.Field:
                //break;
                case SemanticInfoType.ENUM:
                    insertEnum((enumInfo)_info);
                    break;
                case SemanticInfoType.STRUCT:
                    insertStruct(semAst, _nodeId);
                    break;
                case SemanticInfoType.TYPE_ALIAS:
                    insertTypeAlias((typeAliasInfo)_info);
                    break;
                case SemanticInfoType.FUNCTION:
                    insertDeleFun((functionInfo)_info);
                    break;
            }
        }
        //文本中 插入 类型别名
        private void insertTypeAlias(typeAliasInfo info)
        {
            //typedef int* (efef[]);
            string pStr = info.isPoint ? "*" : "";
            string L = info.isArr ? "(" : "";
            string R = info.isArr ? ")" : "";
            string arrStr = info.isArr ? "[]" : "";
            _code += $"{indentSP}{TDF} {info.srcType}{pStr} {L}{info.name}{arrStr}{R};{transTool.LF}";
        }

        //文本中 插入 自定义枚举
        private void insertEnum(enumInfo info)
        {
            //枚举名
            _code += $"{indentSP}enum {info.name}";
            //枚举体开始
            _code += "{" + transTool.LF;

            indentLevel++;//缩进++

            var decls = info.enums_decl;
            for (int i = 0, len = decls.Count; i < len; i += 2)
            {
                var declName = decls[i];
                var declval = decls[i + 1];
                _code += $"{indentSP}{declName} ";

                if (!string.IsNullOrEmpty(declval))
                {
                    //val 是字面 常量
                    _code += $"= {declval}";

                    //val 是表达式
                }
                _code += $",{transTool.LF}";
            }

            indentLevel--;
            //枚举结尾
            _code += indentSP + "};" + transTool.LF;
        }
        //插入结构体
        private void insertStruct(semanticAST semAst, uint nodeID)
        {
            var info = (structInfo)semAst.getSemantInfo(nodeID);
            var node = semAst.getNode(nodeID);
            //结构名
            _code += $"{indentSP}struct {info.name}";
            //结构体开始
            _code += "{" + transTool.LF;
            indentLevel++;//缩进++

            //递归 子类型定义
            var cs = node.children;
            if (cs != null && cs.Count > 0)
            {
                for (int i = 0, len = cs.Count; i < len; i++)
                {
                    insertCType(semAst, cs[i].id);
                }
            }

            //遍历结构体定义
            var decls = info.decls;
            for (int i = 0, len = decls.Count; i < len; i += 2)
            {
                var declType = decls[i];
                var declName = decls[i + 1];

                var arrStr = "";
                //数组处理
                int arrIdx = declType.LastIndexOf("[");
                if (arrIdx != -1)
                {
                    arrStr = declType.Substring(arrIdx);
                    declType = declType.Substring(0, arrIdx);
                }

                _code += $"{indentSP}{declType} {declName}{arrStr};{transTool.LF}";
            }

            indentLevel--;//缩进--
            //结构结尾
            _code += indentSP + "};" + transTool.LF;
        }

        private void insertFunsDic(Dictionary<uint, List<uint>> funIdsDic)
        {
            _code += $"//函数 {transTool.LF}";
            var funList = new List<functionInfo>();
            foreach (var item in funIdsDic)
            {
                uint id = item.Key;
                var funs = item.Value;
                insertFuns(id, funs, funList);
            }

            //cpp loadFun
            insertFunCPPLoader(funList);
        }

        private void insertFunCPPLoader(List<functionInfo> funs)
        {
            _code_c += $"{indentSP_c}int {lDll}(){{{transTool.LF}";
            indentLevel_c++;
            //dll
            _code_c += $"{indentSP_c}HMODULE hDll = LoadLibrary(TEXT(\"{dllFile}\"));{transTool.LF}";
            _code_c += $"{indentSP_c}if (hDll == NULL){{printf(\"load dll {dllFile} error.\\n\", hDll);return -1;}}{transTool.LF}";

            for (int i = 0, len = funs.Count; i < len; i++)
            {
                var info = funs[i];
                //fun 
                _code_c += $"{indentSP_c}{info.name} = ({DE}{info.name})GetProcAddress(hDll, \"{info.name}\");{transTool.LF}";
            }
            indentLevel_c--;
            _code_c += $"{indentSP_c}}}{transTool.LF}";
        }

        //插入函数
        private void insertFuns(uint astId, List<uint> funs, List<functionInfo> colFuns)
        {
            //单个文件
            var semAst = _semAnaly.getSemantAst(astId);
            var node = semAst.node;
            for (int i = 0, len = funs.Count; i < len; i++)
            {
                //.h 中 写入
                var funInfo = (functionInfo)semAst.getSemantInfo(funs[i]);
                insertDeleFun(funInfo, true);
                //函数指针类型别名 声明
                _code += $"{indentSP}{ETN} {DE}{funInfo.name} {funInfo.name};{transTool.LF}";

                //.cpp 中 写入
                _code_c += $"{indentSP_c}{DE}{funInfo.name} {funInfo.name};{transTool.LF}";
                colFuns.Add(funInfo);
            }
        }
        //文本中 插入 函数指针类型声明
        private void insertDeleFun(functionInfo info, bool addDeleTag = false)
        {
            string deleStr = addDeleTag ? DE : "";
            //函数指针类型别名 定义 
            _code += $"{indentSP}{TDF} {info.ret_type} (*{deleStr}{info.name})(";
            //参数
            var args = info.args;
            if (args != null)
            {
                for (int j = 0, len1 = args.Count; j < len1; j += 2)
                {
                    if (j != 0) _code += ",";

                    string _t = args[j];
                    string _name = args[j + 1];
                    string arrStr = "";
                    if (_t != null)
                    {
                        //域符号 修正
                        if (_t.IndexOf(".") != -1)
                        {
                            _t = _t.Replace(".", "::");
                        }

                        int arrIdx = _t.LastIndexOf("[");
                        if (arrIdx != -1)
                        {
                            arrStr = _t.Substring(arrIdx);
                            _t = _t.Substring(0, arrIdx);
                        }
                    }

                    //参类型 
                    _code += _t + transTool.SP;
                    //参名
                    if (string.IsNullOrEmpty(_name)) continue;
                    _code += _name;
                    if (!string.IsNullOrEmpty(arrStr))
                    {
                        _code += arrStr;
                    }
                }
            }

            _code += $");{transTool.LF}";
        }

        public void Dispose()
        {
            //
            _semAnaly = null;
        }
    }
}
